function isObject(obj: any) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

export const merge = (...objs: any[]): any => {
  const ensureObjs = objs.filter((obj) => obj !== undefined && obj !== null);
  if (ensureObjs.length === 0) {
    return null;
  } else if (ensureObjs.length === 1) {
    return ensureObjs[0];
  } else {
    const result = ensureObjs.reduce((previousValue: any, obj: any): any => {
      if (isObject(obj)) {
        Object.keys(obj).forEach((key): any => {
          previousValue[key] = merge(previousValue[key], obj[key]);
        });
        return previousValue;
      } else if (Array.isArray(obj) && Array.isArray(previousValue)) {
        const newArr = [...previousValue];
        newArr.push(...obj);
        return [...new Set(newArr)];
      } else {
        return obj;
      }
    }, {});
    return isObject(result) ? {...result} : result;
  }
};
